/*
 * @file     g_hspi.c
 * @brief    source file for setting high speed spi
 *
 * Change Logs:
 * Date            Author             Version        Notes
 * 2020-11-12      zhupengkun         V1.0.0         the first version
 * 2021-02-02      dengzhiqian        V1.1.0         Modify the register module configuration
 */

#include "g_hspi.h"

/**
  * @method hspi
  * @brief  Deinitializes the HSPI registers to their default reset values.
  * @param  None
  * @retval None
  */
void G_HSPI_DeInit(void)
{
    MHSPI->CTRL.reg                = 0;
    MHSPI->DMA.reg                 = 0;
    MHSPI->DMA_RX_SADDR.reg        = 0;
    MHSPI->DMA_TX_SADDR.reg        = 0;
    MHSPI->DMA_TX_LEN.reg          = 0;
    MHSPI->DMA_RX_LEN.reg          = 0;
    MHSPI->DMA_TX_LEN.reg          = 0;
    MHSPI->FIFO.reg                = 0;
    MHSPI->IRQ.reg                 = 0;
}

/**
  * @method hspi
  * @brief  Initializes the HSPI according to the specified parameters in the HSPI_InitStruct.
  * @param  HSPI_InitStruct: pointer to a G_HSPI_InitTypeDef structure that contains
  *         the configuration information for the HSPI.
  * @retval None
  */
void G_HSPI_Init(G_HSPI_InitTypeDef* HSPI_InitStruct)
{
    _ASSERT(Is_HSPI_Mode(HSPI_InitStruct->SlaveMode));
    _ASSERT(Is_HSPI_TxRx_Sequence(HSPI_InitStruct->TxRxSeq));
    _ASSERT(Is_HSPI_CPHA(HSPI_InitStruct->CPHA));
    _ASSERT(Is_HSPI_CPOL(HSPI_InitStruct->CPOL));
    _ASSERT(Is_HSPI_Hw_Start_Sel(HSPI_InitStruct->SpiHwStartSel));
    _ASSERT(IS_HSPI_CTRL_RXADJCLK(HSPI_InitStruct->RxAdjClk));
    _ASSERT(IS_HSPI_CTRL_TXRXDLY(HSPI_InitStruct->TxRxDly));
    _ASSERT(IS_HSPI_CTRL_NCSDLY(HSPI_InitStruct->NcsDly));


    MHSPI->CTRL.reg |=  HSPI_InitStruct->SlaveMode << HSPI_CTRL_SLAVE_MODE_BIT|\
                    ((HSPI_InitStruct->RxAdjClk & 0x0f) << HSPI_CTRL_RX_ADJ_CLK_BIT)|\
                    ((HSPI_InitStruct->ClkDiv & 0x0f) << HSPI_CTRL_CLK_DIV_BIT)|\
                    ((HSPI_InitStruct->TxRxDly & 0x0f) << HSPI_CTRL_TRX_DLY_BIT)|\
                    ((HSPI_InitStruct->NcsDly & 0x07) << HSPI_CTRL_NCS_DLY_BIT)|\
                    ((HSPI_InitStruct->RxAdjEn & 0x01) << HSPI_CTRL_RX_ADJ_EN_BIT)|\
                        HSPI_InitStruct->TxRxSeq |\
                        HSPI_InitStruct->CPHA |\
                        HSPI_InitStruct->CPOL |\
                        HSPI_InitStruct->SpiHwStartSel;

}

/**
  * @method hspi
  * @brief  Enables or disables the HSPI hardware start.
  * @param  newstate: new state of the HSPI hardware start.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void G_HSPI_HwStartCmd(G_FunctionalState newstate)
{
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        /* Enable the HSPI Hw Start */
        MHSPI->CTRL.reg |= (1 << HSPI_HW_START_ENABLE_BIT);
    }
    else
    {
        /* Disable the HSPI Hw Start */
        MHSPI->CTRL.reg &= ~(1 << HSPI_HW_START_ENABLE_BIT);
    }
}

/**
  * @method hspi
  * @brief  Enables or disables the HSPI interface.
  * @param  newstate: new state of the HSPI interface.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void G_HSPI_EnableCmd(G_FunctionalState newstate)
{
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        /* Enable the HSPI */
        MHSPI->CTRL.reg |= (1 << HSPI_ENABLE_BIT);
    }
    else
    {
        /* Disable the HSPI */
        MHSPI->CTRL.reg &= ~(1 << HSPI_ENABLE_BIT);
    }
}

/**
  * @method hspi
  * @brief  Enables or disables the HSPI DMA ping-pang display.
  * @param  newstate: new state of the HSPI DMA ping-pang display.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void G_HSPI_PingpangEnableCmd(G_FunctionalState newstate)
{
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        /* Enable the HSPI DMA PINGPANG */
        MHSPI->DMA.reg |= (1 << HSPI_PINGPANG_ENABLE_BIT);
    }
    else
    {
        /* Disable the HSPI DMA PINGPANG */
        MHSPI->DMA.reg &= ~(1 << HSPI_PINGPANG_ENABLE_BIT);
    }
}

/**
  * @method hspi
  * @brief  Enables or disables the HSPI DMA.
  * @param  newstate: new state of the HSPI DMA.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void G_HSPI_DmaEnableCmd(G_FunctionalState newstate)
{
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        /* Enable the HSPI DMA */
        MHSPI->DMA.reg |= (1 << HSPI_DMA_ENABLE_BIT);
    }
    else
    {
        /* Disable the HSPI DMA */
        MHSPI->DMA.reg &= ~(1 << HSPI_DMA_ENABLE_BIT);
    }
}

/**
  * @method hspi
  * @brief  Enables or disables the HSPI DMA auto start.
  * @param  newstate: new state of the HSPI DMA auto start.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void G_HSPI_DmaAutoStartCmd(G_FunctionalState newstate)
{
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        /* Enable the HSPI DMA Auto Start */
        MHSPI->DMA.reg |= (1 << HSPI_DMA_AUTO_START_BIT);
    }
    else
    {
        /* Disable the HSPI DMA Auto Start */
        MHSPI->DMA.reg &= ~(1 << HSPI_DMA_AUTO_START_BIT);
    }
}

/**
  * @method hspi
  * @brief  Enables or disables the HSPI interface interrupts.
  * @param  irq: specifies the HSPI interrupt sources to be enabled or disabled.
  *         This parameter can be any combination of the following values:
  *                 @arg Start_Over_Quick_IRQ: Start over quick interrupt
  *                 @arg RxFifo_Overflow_IRQ: Rx fifo overflow interrupt
  *                 @arg RxFifo_High_IRQ: Rx fifo high interrupt
  *                 @arg TxFifo_Overflow_IRQ: Tx fifo overflow interrupt
  *                 @arg TxFifo_Low_IRQ: Tx fifo low interrupt
  *                 @arg DMA_Done_IRQ: DMA done interrupt
  * @param  newstate: new state of the specified HSPI interrupts.
  *         This parameter can be: ENABLE or DISABLE.
  * @retval None
  */
void G_HSPI_ITConfig(unsigned int irq, G_FunctionalState newstate)
{
    _ASSERT(Is_HSPI_IRQ_Config(irq));
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        /* Enable the Interrupt sources */
        MHSPI->IRQ.reg |= (irq << HSPI_IRQ_DONE_EN);
    }
    else
    {
        /* Disable the Interrupt sources */
        MHSPI->IRQ.reg &= ~(irq << HSPI_IRQ_DONE_EN);
    }
}

/**
  * @method hspi
  * @brief  Clears the HSPI's interrupt pending bits.
  * @param  irq: specifies the HSPI interrupt pending bit to clear.
  *         This parameter can be any combination of the following values:
  *             @arg Start_Over_Quick_IRQ: Start over quick interrupt
  *             @arg RxFifo_Overflow_IRQ: Rx fifo overflow interrupt
  *             @arg RxFifo_High_IRQ: Rx fifo high interrupt
  *             @arg TxFifo_Overflow_IRQ: Tx fifo overflow interrupt
  *             @arg TxFifo_Low_IRQ: Tx fifo low interrupt
  *             @arg DMA_Done_IRQ: DMA done interrupt
  * @param  newstate: new state of the specified HSPI interrupts.
  *         This parameter can be: ENABLE(Clear) or DISABLE.
  *         Need DISABLE after ENABLE(Clear).
  * @retval None
  */
void G_HSPI_ITClear(unsigned int irq, G_FunctionalState newstate)
{
    _ASSERT(Is_HSPI_IRQ_Clear(irq));
    _ASSERT(IS_FUNCTIONAL_STATE(newstate));

    if (newstate != DISABLE)
    {
        MHSPI->IRQ.reg |= (irq << HSPI_IRQ_DONE_MIS);
        MHSPI->IRQ.reg |= (irq);
    }
    else
    {
        MHSPI->IRQ.reg &= ~(irq << HSPI_IRQ_DONE_MIS);
        MHSPI->IRQ.reg &= ~(irq);
    }
}

/**
  * @method hspi
  * @brief  Checks whether the HSPI interface flag is set or not.
  * @param  irq: specifies the flag to check.
  *         This parameter can be one of the following values:
  *             @arg Start_Over_Quick_RIS: Start over quick raw interrupt status
  *             @arg RxFifo_Overflow_RIS: Rx fifo overflow raw interrupt status
  *             @arg RxFifo_High_RIS: Rx fifo high raw interrupt status
  *             @arg TxFifo_Overflow_RIS: Tx fifo overflow raw interrupt status
  *             @arg TxFifo_Low_RIS: Tx fifo low raw interrupt status
  *             @arg DMA_Done_RIS: DMA done raw interrupt status
  *             @arg Start_Over_Quick_MIS: Start over quick mask interrupt status
  *             @arg RxFifo_Overflow_MIS: Rx fifo overflow mask interrupt status
  *             @arg RxFifo_High_MIS: Rx fifo high mask interrupt status
  *             @arg TxFifo_Overflow_MIS: Tx fifo overflow mask interrupt status
  *             @arg TxFifo_Low_MIS: Tx fifo low mask interrupt status
  *             @arg DMA_Done_MIS: DMA done mask interrupt status
  * @retval SET or RESET
  */
G_FlagStatus G_HSPI_GetITStatus(unsigned int irq)
{
    G_FlagStatus bitstatus = RESET;
    volatile unsigned int tempreg = 0;

    _ASSERT(Is_HSPI_Get_IRQ_Status(irq));

    if ((irq) & 0x100000) /* The FLAG is in RISR register */
    {
        tempreg = MHSPI->IRQ.reg & 0x3f;
    }
    else /* The FLAG is in MISR register */
    {
        tempreg = (MHSPI->IRQ.reg >> 8) & 0x3f;
    }

    if ((tempreg & irq) != RESET)
    {
        bitstatus = SET;
    }
    else
    {
        bitstatus = RESET;
    }
    /* Return the DCMI_FLAG status */
    return  bitstatus;
}

/**
  * @method hspi
  * @brief  Transmits one data via HSPI DMA.
  * @param  data: the data you want transmit.
  * @retval None
  */
void G_HSPI_SendData(unsigned char data)
{
    volatile unsigned int pdata = data;
    MHSPI->DMA_TX_SADDR.reg = (unsigned int)(&pdata);
    MHSPI->DMA_TX_LEN.reg = 0x01;
    MHSPI->DMA_RX_LEN.reg = 0x00;
    MHSPI->CTRL.reg |= 1 << HSPI_START_BIT;
    while (!(G_HSPI_GetITStatus(DMA_Done_RIS)));
    G_HSPI_ITClear(DMA_Done_IRQ, ENABLE);
}

/**
  * @method hspi
  * @brief  Transmits datas via HSPI DMA.
  * @param  txbuff: pointer to a buf that contains the data you want send.
  * @param  txlen: the buf length
  * @retval None
  */
void G_HSPI_SendBuff(unsigned char *txbuff, unsigned int txlen)
{
    if (txlen < 1)
    {
        return;
    }
		
		
    MHSPI->DMA_TX_SADDR.reg = (unsigned int)txbuff;
    MHSPI->DMA_TX_LEN.reg = txlen & 0xfffff;
    MHSPI->DMA_RX_LEN.reg = 0x00;
    MHSPI->CTRL.reg |= 1 << HSPI_START_BIT;
    while (!(G_HSPI_GetITStatus(DMA_Done_RIS)));
    G_HSPI_ITClear(DMA_Done_IRQ, ENABLE);
}

/**
  * @method hspi
  * @brief  Transmits datas via HSPI DMA.
  * @param  txbuff: pointer to a buf that contains the data you want send.
  * @param  txlen: the buf length
  * @retval None
  */
static int HSPI_sendflag = 0;
void G_HSPI_DMASendBuff(unsigned char *txbuff, unsigned int txlen)
{
    if (txlen < 1)
    {
        return;
    }
		
    MHSPI->DMA_TX_SADDR.reg = (unsigned int)txbuff;
    MHSPI->DMA_TX_LEN.reg = txlen & 0xfffff;
    MHSPI->DMA_RX_LEN.reg = 0x00;
    MHSPI->CTRL.reg |= 1 << HSPI_START_BIT;	
    HSPI_sendflag = 1;
}

/**
  * @method hspi
  * @brief  HSPI DMA busy.
  * @param  NULL.
  * @retval 1: busy 0: not busy
  */
uint8_t G_HSPI_DMASendBusy(void)
{
    uint8_t ret = 0;
    if (HSPI_sendflag == 1)
    {
        if(G_HSPI_GetITStatus(DMA_Done_RIS))
        {
            ret = 0;
            HSPI_sendflag = 0;
            G_HSPI_ITClear(DMA_Done_IRQ, ENABLE);
        }
        else
        {
            ret = 1;
        }
    }
    return ret;
}

/**
  * @method hspi
  * @brief  recerive data.
  * @param: rxbuff: pointer to a Rxbuff  that contains the data you want receive.
  * @param: rxlen: the length of receive datas
  * @retval None
  */
void G_HSPI_ReceiveData(unsigned char *rxbuff, unsigned int rxlen)
{
    if (rxlen < 1)
    {
        return;
    }

    MHSPI->DMA_RX_SADDR.reg = (unsigned int)rxbuff;
    MHSPI->DMA_TX_LEN.reg = 0x00;
    MHSPI->DMA_RX_LEN.reg  = rxlen & 0xfffff;
    MHSPI->CTRL.reg |= 1 << HSPI_START_BIT;
    while (!(G_HSPI_GetITStatus(DMA_Done_RIS)));
    G_HSPI_ITClear(DMA_Done_IRQ, ENABLE);
}

/**
  * @method hspi
  * @brief  Send and recerive data.
  * @param: txbuff: pointer to a txbuff  that contains the data you want send.
  * @param: txlen: the length of send datas
  * @param: rxbuff: pointer to a txbuff  that contains the data you want receive.
  * @param: rxlen: the length of receive datas
  * @retval None
  */
void G_HSPI_SendAndReceiveData(unsigned char *txbuff, unsigned int txlen, unsigned char *rxbuff, unsigned int rxlen)
{
    if (txlen < 1)
    {
        return;
    }

    MHSPI->DMA_TX_SADDR.reg = (unsigned int)txbuff;
    MHSPI->DMA_RX_SADDR.reg = (unsigned int)rxbuff;
    MHSPI->DMA_TX_LEN.reg = txlen & 0xfffff;
    MHSPI->DMA_RX_LEN.reg  = rxlen & 0xfffff;
    MHSPI->CTRL.reg |= 1 << HSPI_START_BIT;
    while (!(G_HSPI_GetITStatus(DMA_Done_RIS)));
    G_HSPI_ITClear(DMA_Done_IRQ, ENABLE);
}
